#!/bin/bash
{
	#////////////////////////////////////
	# DietPi CPU Gov Script
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - Location: /boot/dietpi/func/dietpi-set_cpu
	# - Runs at boot, called by /boot/dietpi/preboot
	# - Applies CPU governor: ondemand, powersave, performance, etc.
	# - Applies CPU governor settings: throttle up percent etc.
	#////////////////////////////////////

	# Exit if not supported
	if [[ ! -f '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors' ]]; then

		echo 'DietPi-CPU_set | CPU governors are not supported on this device. Aborting...'
		exit

	fi

	# Import DietPi-Globals --------------------------------------------------------------
	. /boot/dietpi/func/dietpi-globals
	readonly G_PROGRAM_NAME='DietPi-CPU_set'
	G_CHECK_ROOT_USER
	G_INIT
	# Import DietPi-Globals --------------------------------------------------------------

	CPU_GOVERNOR=$(sed -n '/^[[:blank:]]*CONFIG_CPU_GOVERNOR=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)
	[[ $CPU_GOVERNOR ]] || CPU_GOVERNOR='schedutil'

	Check_CPU_Gov_Available(){

		local available_governors=$(</sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors)

		# Check if target Gov is available on system
		if [[ $available_governors != *"$CPU_GOVERNOR"* ]]; then

			G_DIETPI-NOTIFY 1 "CPU governor $CPU_GOVERNOR is not supported by kernel"

			if [[ $available_governors == *'schedutil'* ]]; then

				CPU_GOVERNOR='schedutil'

			elif [[ $available_governors == *'ondemand'* ]]; then

				CPU_GOVERNOR='ondemand'

			elif [[ $available_governors == *'interactive'* ]]; then

				CPU_GOVERNOR='interactive'

			else

				CPU_GOVERNOR='performance'

			fi

			G_DIETPI-NOTIFY 2 "Switching to CPU governor: $CPU_GOVERNOR"

			# Update dietpi.txt
			G_CONFIG_INJECT 'CONFIG_CPU_GOVERNOR=' "CONFIG_CPU_GOVERNOR=$CPU_GOVERNOR" /boot/dietpi.txt

		fi

	}

	Apply_CPU_Gov(){

		# Apply governor
		local i
		for i in /sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_governor
		do

			echo "$CPU_GOVERNOR" > "$i"

		done

		# Apply CPU max/min frequency
		# - Only on non-RPi
		if (( $G_HW_MODEL > 9 )); then

			local cpu_max_freq=$(sed -n '/^[[:blank:]]*CONFIG_CPU_MAX_FREQ=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)
			local cpu_min_freq=$(sed -n '/^[[:blank:]]*CONFIG_CPU_MIN_FREQ=/{s/^[^=]*=//p;q}' /boot/dietpi.txt)

			# Intel based 0-100%
			if [[ -f '/sys/devices/system/cpu/intel_pstate/max_perf_pct' ]]; then

				disable_error=1 G_CHECK_VALIDINT "$cpu_max_freq" 1 100 || cpu_max_freq=100
				disable_error=1 G_CHECK_VALIDINT "$cpu_min_freq" 1 100 || cpu_min_freq=25

				G_DIETPI-NOTIFY 2 "Setting CPU frequency limits : Max = $cpu_max_freq % | Min = $cpu_min_freq %"

				echo $cpu_max_freq > /sys/devices/system/cpu/intel_pstate/max_perf_pct
				echo $cpu_min_freq > /sys/devices/system/cpu/intel_pstate/min_perf_pct

				if [[ -f '/sys/devices/system/cpu/intel_pstate/no_turbo' ]]; then

					if grep -qi '^[[:blank:]]*CONFIG_CPU_DISABLE_TURBO=1' /boot/dietpi.txt; then

						G_DIETPI-NOTIFY 2 'Disabling Intel Turbo Mode'
						echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo

					else

						G_DIETPI-NOTIFY 2 'Enabling Intel Turbo Mode'
						echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo

					fi

				else

					G_DIETPI-NOTIFY 2 'Intel Turbo Mode is not supported on this device'

				fi

			# Standard via kernel (MHz)
			elif [[ -f '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq' ]]; then

				# Reset to defaults if no/invalid entry
				local converted_khz_value_max=-1 # -1 indicates reset CPU freqs
				local converted_khz_value_min=-1 # -1 indicates reset CPU freqs
				disable_error=1 G_CHECK_VALIDINT "$cpu_max_freq" 1 && converted_khz_value_max=$(( $cpu_max_freq * 1000 )) # MHz => kHz
				disable_error=1 G_CHECK_VALIDINT "$cpu_min_freq" 1 && converted_khz_value_min=$(( $cpu_min_freq * 1000 )) # MHz => kHz

				G_DIETPI-NOTIFY 2 "Setting CPU frequency limits : Max = $cpu_max_freq MHz | Min = $cpu_min_freq MHz"

				for i in /sys/devices/system/cpu/cpu[0-9]*/cpufreq
				do

					if (( $converted_khz_value_min > 0 )); then

						echo "$converted_khz_value_min" > "$i/scaling_min_freq"

					else

						mawk '{print $1}' "$i/scaling_available_frequencies" > "$i/scaling_min_freq"

					fi

					if (( $converted_khz_value_max > 0 )); then

						echo "$converted_khz_value_max" > "$i/scaling_max_freq"

					else

						mawk '{print $NF}' "$i/scaling_available_frequencies" > "$i/scaling_max_freq"

					fi

				done

			else

				G_DIETPI-NOTIFY 2 'CPU frequency limits are not supported on this device'

			fi

		fi

		local cpu_throttle_up_percent=$(sed -n '/^[[:blank:]]*CONFIG_CPU_USAGE_THROTTLE_UP=/{s/[^=]*=//p;q}' /boot/dietpi.txt)

		# Set CPU governor interactive settings
		if [[ $CPU_GOVERNOR == 'interactive' ]]; then

			# Set hispeed_load, if available on system (eg: XU4 kernel lacks this feature)
			if [[ -f '/sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load' ]]; then

				G_DIETPI-NOTIFY 2 "Setting go_hispeed_load: $cpu_throttle_up_percent %"
				echo "$cpu_throttle_up_percent" > /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load

			else

				G_DIETPI-NOTIFY 2 'go_hispeed_load is not supported on your device'

			fi

		# Set CPU governor ondemand settings
		elif [[ $CPU_GOVERNOR == 'ondemand' ]]; then

			local cpu_ondemand_sampling_rate=$(sed -n '/^[[:blank:]]*CONFIG_CPU_ONDEMAND_SAMPLE_RATE=/{s/[^=]*=//p;q}' /boot/dietpi.txt)
			local cpu_ondemand_sampling_down_factor=$(sed -n '/^[[:blank:]]*CONFIG_CPU_ONDEMAND_SAMPLE_DOWNFACTOR=/{s/[^=]*=//p;q}' /boot/dietpi.txt)

			G_DIETPI-NOTIFY 2 "Setting up_threshold: $cpu_throttle_up_percent %"
			G_DIETPI-NOTIFY 2 "Setting sampling_rate: $cpu_ondemand_sampling_rate microseconds"
			G_DIETPI-NOTIFY 2 "Setting sampling_down_factor: $cpu_ondemand_sampling_down_factor"

			# Check for different possible locations
			# - All
			if [[ -f '/sys/devices/system/cpu/cpufreq/ondemand/up_threshold' ]]; then

				echo "$cpu_throttle_up_percent" > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold
				echo "$cpu_ondemand_sampling_rate" > /sys/devices/system/cpu/cpufreq/ondemand/sampling_rate
				echo "$cpu_ondemand_sampling_down_factor" > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor

			# - XU4 3.x kernel
			elif [[ -f '/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold' ]]; then

				# Apply to all cores
				for i in /sys/devices/system/cpu/cpu[0-9]*/cpufreq/ondemand
				do

					echo "$cpu_throttle_up_percent" > "$i/up_threshold"
					echo "$cpu_ondemand_sampling_rate" > "$i/sampling_rate"
					echo "$cpu_ondemand_sampling_down_factor" > "$i/sampling_down_factor"

				done

			else

				G_DIETPI-NOTIFY 2 'up_threshold is not supported on your device'

			fi

		# Set CPU governor conservative settings
		elif [[ $CPU_GOVERNOR == 'conservative' ]]; then

			G_DIETPI-NOTIFY 2 "Setting up_threshold: $cpu_throttle_up_percent %"

			# XU3/4 different path (must apply to each core)
			if [[ $G_HW_MODEL != 11 && -f '/sys/devices/system/cpu/cpufreq/conservative/up_threshold' ]]; then

				echo "$cpu_throttle_up_percent" > /sys/devices/system/cpu/cpufreq/conservative/up_threshold

			elif [[ -f '/sys/devices/system/cpu/cpu0/cpufreq/conservative' ]]; then

				for i in /sys/devices/system/cpu/cpu[0-9]*/cpufreq/conservative
				do

					echo "$cpu_throttle_up_percent" > "$i/up_threshold"

				done

			else

				G_DIETPI-NOTIFY 2 'up_threshold is not supported on your device'

			fi

		fi

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Main Loop
	#/////////////////////////////////////////////////////////////////////////////////////
	#-----------------------------------------------------------------------------------
	G_DIETPI-NOTIFY 3 "$G_PROGRAM_NAME" "Applying CPU governor settings: $CPU_GOVERNOR"
	#-----------------------------------------------------------------------------------
	Check_CPU_Gov_Available

	# Apply CPU0 gov to all cores (if required)
	Apply_CPU_Gov

	G_DIETPI-NOTIFY 0 "Applied CPU governor settings: $CPU_GOVERNOR"

	#-----------------------------------------------------------------------------------
	exit
	#-----------------------------------------------------------------------------------
}
